<?php
/**
 * Created by PhpStorm.
 * User: zlkmu
 * Date: 2017/10/25
 * Time: 22:49
 * 专门用于判断麻将胡牌，碰牌，杠牌的类
 */

    class MajangLogic{

        /**
         * 检查能否碰牌的函数
         * @param $playerPai 玩家的手牌
         * @param $pai 打出来的具体牌
         * @return 如果能碰，true
         *         否则,false
         */
        function checkPeng($playerPai, $pai){
            $count = 0;
            for($i = 0; $i < count($playerPai); $i++){
                if($playerPai[$i] == $pai){
                    $count++;
                }
            }
            if($count >= 2){
                return true;
            }
            else{
                return false;
            }
        }

        /**
         * 检查能否杠牌的函数
         * @param $playerPai 玩家的手牌
         * @param $playerPeng 玩家碰过的牌
         * @param $pai 打出来的具体牌
         * @return 如果能杠，MINGGANG/ ANGANG
         *         否则，返回false
         */
        function checkGang($playerPai, $playerPeng, $pai){
            $count = 0;
            for($i = 0; $i < count($playerPai); $i++){
                if($playerPai[$i] == $pai){
                    $count++;
                }
            }
            if($count == 3){
                return AN_GANG;
            }
            else{
                for($i = 0; $i < count($playerPeng); $i++){
                    if($playerPeng[$i] == $pai){
                        return MING_GANG;
                    }
                }
                return false;
            }
        }

        /**
         * 处理玩家手牌的函数，将打过来的牌或者摸得牌放入数组并排序
         * @param $playerPai，玩家的手牌
         * @param $pai，玩家摸到或者打给玩家的牌
         */
        private function processPlayerPai($playerPai, $pai){
            array_push($playerPai, $pai);
            sort($playerPai);
            return $playerPai;
        }

        /**
         * 检查能否胡牌的函数
         * @param $playerPai,玩家当前的手牌
         * @param $pai，玩家摸到或者打给玩家的牌
         * @return false / true
         */
        function checkHu($playerPai, $pai){

            $huPaiCheck = $this->processPlayerPai($playerPai, $pai);

            //普通胡牌检测
            $r =  $this->doCheckHu($huPaiCheck);

            if(!$r)
                //七对胡牌检测
                $r = $this->canSevenHu($huPaiCheck);
            return $r;
        }

        /**
         * 辅助checkHu检查胡牌的函数
         * @param $checkArray  由checkHu组合的字符串
         * @return bool 返回是否能胡牌
         */
        private function doCheckHu($checkArray){
            //如果只有两张牌
            if(count($checkArray) == 2){
                return $checkArray[0] == $checkArray[1];
            }

            $canHu = false;
            //找出将牌
            for($i = 0; $i < count($checkArray) - 1; $i++){
                //如果当前牌和后一张一样，则可为将
                if($checkArray[$i] == $checkArray[$i+1]){
                    //如果将牌所在位置位于倒数第二个位置，直接截取前面所有的牌作为判断
                    if($i == count($checkArray) - 2){
                        $tempArray = array_slice($checkArray, 0, $i);
                    }
                    //如果将牌在一开始的位置，只截取后面的牌作为判断
                    else if($i == 0){
                        $tempArray = array_slice($checkArray, $i+2, count($checkArray) - 2);
                    }
                    //否则，从0到将牌所在位置，并从跳过将牌的位置到最后分别截取数组，合并成一个判断数组
                    else{
                        $tempArray1 = array_slice($checkArray, $i+2, count($checkArray) - $i - 2);
                        $tempArray2 = array_slice($checkArray, 0, $i);
                        $tempArray = array_merge($tempArray1, $tempArray2);
                    }
                    //判断剩余牌组是否符合AAA 或ABC组合，则可以得出能否胡牌
                    if($this->canHu($tempArray)){
                        return true;
                    }

                }
            }
            return false;

        }

        /**
         * 辅助doCheckHu检查胡牌的函数
         * @param $checkPais  由doCheckHu分割形成的除了将牌的手牌
         * @return bool 返回是否能胡牌
         */
        private function canHu($checkPais){
            //如果截取的牌组为0,则已经可以胡牌了，这种情况不会发生
            if(count($checkPais) == 0){
                return true;
            }
            //否则从第一张开始，每三张牌作为一组判断，因为排除将以后剩下的牌只可能是3,6,9,12这4种情况
            for($i = 0; $i < count($checkPais); $i+= 3){
                $tempArray = array_slice($checkPais, $i, 3);
                //防止错误的情况，这种情况应该不会发生
                if(count($tempArray) < 3){
                    return false;
                }
                //如果形成坎子，继续判断
                if( ($tempArray[0] == $tempArray[1]) && ($tempArray[1] == $tempArray[2])){
                    conutinue;
                }
                //如果形成顺子，继续判断
                else if(($tempArray[0] + 1 == $tempArray[1]) && ($tempArray[1]+1 == $tempArray[2])){
                    continue;
                }
                //否则不能胡，直接返回
                else
                    return false;
            }

            return true;

        }

        /**
         * 检查七小队/龙七对能胡的函数
         * @param $checkPai
         * @return bool true or false表示能否胡牌
         */
        private function canSevenHu($checkPai){
            if(count($checkPai) != 14){
                return false;
            }

            $pairCount = 0;
            for($i = 0; $i < count($checkPai); $i += 2){
                if($checkPai[$i] == $checkPai[$i+1]){
                    $pairCount++;
                }
            }
            return $pairCount == 7;
        }

        /**
         * 检查是否能够推牌的函数，其实就是查叫，看看当玩家摸到一张牌后，打出任意一张牌后，是否能听牌
         * @param $playerPai 玩家的手牌
         * @param $pai 玩家摸到的牌
         * @return array  (i=>array(打的什么牌, array(a, b, c)具体胡的牌)
         */

        function canTingPai($playerPai, $pai){
             $tingArray = array();
             $checkTingPai = $this->processPlayerPai($playerPai, $pai);

             //基本思路，假设打出任意一张牌，且加入任意一张牌能胡牌，那这张牌就可以听牌
            for($i = 0; $i < count($checkTingPai); $i++){
                //保存现有牌组
                $tempArray = $checkTingPai;
                //按照顺序，从牌组中移除第i张牌，相当于打了这张牌
                array_splice($tempArray, $i, 1);
                //检查能否听牌
                $r = $this->doCheckTingPai($tempArray);

                if(count($r) > 0){
                    array_push($tingArray, array($checkTingPai[$i], $r));
                }
            }
            return $tingArray;

        }

        /**
         * 实际检测听牌的函数，基本思路为遍历所有牌型
         * @param $processedPai
         * @return array
         */
        private function doCheckTingPai($processedPai){
            //记录能胡牌的数组，也就是在打出某张牌后能听的牌
            $result = array();
            //便利所有牌
            for($i = 0; $i < 3; $i++){
                for($j = 1; $j <= 9; $j++){
                    //先保存现有牌型
                    $tempArray = $processedPai;
                    //压入任意牌型
                    array_push($tempArray, $i * 10 + $j);
                    //排序
                    sort($tempArray);
                    //检查当前牌组能否胡牌
                    $r = $this->doCheckHu($tempArray);
                    //如果可以，则为所听的牌
                    if($r){
                        array_push($result, $i*10+$j);
                    }
                    //检查特殊牌型能不能胡牌
                    $r = $this->canSevenHu($processedPai);
                    if($r)
                        array_push($result, $i * 10 + $j);
                }
            }
            return $result;
        }

        /**
         * 获取番数的函数，
         * @param $playerPai 玩家手牌
         * @param $pengPai 玩家碰的牌
         * @param $gangPai 玩家杠的牌
         * @param $roomType 房间原因的加牌
         */
        public function getPaiFanShu($playerPai, $pengPai, $gangPai, $roomType){

        }






    }


?>